/* SPDX-License-Identifier: BSD-3-Clause */
/* Copyright(c) 2007-2022 Intel Corporation */
#include "qat_freebsd.h"
#include "adf_cfg.h"
#include "adf_common_drv.h"
#include "adf_accel_devices.h"
#include "icp_qat_uclo.h"
#include "icp_qat_fw.h"
#include "icp_qat_fw_init_admin.h"
#include "adf_cfg_strings.h"
#include "adf_transport_access_macros.h"
#include "adf_transport_internal.h"
#include "adf_heartbeat.h"
#include <sys/types.h>
#include <sys/lock.h>
#include <sys/sx.h>
#include <sys/malloc.h>
#include <sys/systm.h>
#include <dev/pci/pcivar.h>
#include <machine/bus_dma.h>

#include <linux/delay.h>

#define ADF_CONST_TABLE_VERSION_BYTE (0)
/* Keep version number in range 0-255 */
#define ADF_CONST_TABLE_VERSION (1)

/* Admin Messages Registers */
#define ADF_MAILBOX_STRIDE 0x1000
#define ADF_ADMINMSG_LEN 32
#define FREEBSD_ALLIGNMENT_SIZE 64
#define ADF_INIT_CONFIG_SIZE 1024

static u8 const_tab[1024] __aligned(1024) = {
ADF_CONST_TABLE_VERSION,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x02, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x13, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76,
0x54, 0x32, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x45, 0x23, 0x01, 0xef, 0xcd, 0xab,
0x89, 0x98, 0xba, 0xdc, 0xfe, 0x10, 0x32, 0x54, 0x76, 0xc3, 0xd2, 0xe1, 0xf0,
0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0x05, 0x9e,
0xd8, 0x36, 0x7c, 0xd5, 0x07, 0x30, 0x70, 0xdd, 0x17, 0xf7, 0x0e, 0x59, 0x39,
0xff, 0xc0, 0x0b, 0x31, 0x68, 0x58, 0x15, 0x11, 0x64, 0xf9, 0x8f, 0xa7, 0xbe,
0xfa, 0x4f, 0xa4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6a, 0x09, 0xe6, 0x67, 0xbb, 0x67, 0xae,
0x85, 0x3c, 0x6e, 0xf3, 0x72, 0xa5, 0x4f, 0xf5, 0x3a, 0x51, 0x0e, 0x52, 0x7f,
0x9b, 0x05, 0x68, 0x8c, 0x1f, 0x83, 0xd9, 0xab, 0x5b, 0xe0, 0xcd, 0x19, 0x05,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xcb, 0xbb, 0x9d, 0x5d, 0xc1, 0x05, 0x9e, 0xd8, 0x62, 0x9a, 0x29,
0x2a, 0x36, 0x7c, 0xd5, 0x07, 0x91, 0x59, 0x01, 0x5a, 0x30, 0x70, 0xdd, 0x17,
0x15, 0x2f, 0xec, 0xd8, 0xf7, 0x0e, 0x59, 0x39, 0x67, 0x33, 0x26, 0x67, 0xff,
0xc0, 0x0b, 0x31, 0x8e, 0xb4, 0x4a, 0x87, 0x68, 0x58, 0x15, 0x11, 0xdb, 0x0c,
0x2e, 0x0d, 0x64, 0xf9, 0x8f, 0xa7, 0x47, 0xb5, 0x48, 0x1d, 0xbe, 0xfa, 0x4f,
0xa4, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x6a, 0x09, 0xe6, 0x67, 0xf3, 0xbc, 0xc9, 0x08, 0xbb,
0x67, 0xae, 0x85, 0x84, 0xca, 0xa7, 0x3b, 0x3c, 0x6e, 0xf3, 0x72, 0xfe, 0x94,
0xf8, 0x2b, 0xa5, 0x4f, 0xf5, 0x3a, 0x5f, 0x1d, 0x36, 0xf1, 0x51, 0x0e, 0x52,
0x7f, 0xad, 0xe6, 0x82, 0xd1, 0x9b, 0x05, 0x68, 0x8c, 0x2b, 0x3e, 0x6c, 0x1f,
0x1f, 0x83, 0xd9, 0xab, 0xfb, 0x41, 0xbd, 0x6b, 0x5b, 0xe0, 0xcd, 0x19, 0x13,
0x7e, 0x21, 0x79, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x18,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x15, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x02, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x14, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x24, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x12, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x2B, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

#define ADF_ADMIN_POLL_INTERVAL_US 20
#define ADF_ADMIN_POLL_RETRIES 5000

static void
dma_callback(void *arg, bus_dma_segment_t *segs, int nseg, int error)
{
	bus_addr_t *addr;

	addr = arg;
	if (error == 0 && nseg == 1)
		*addr = segs[0].ds_addr;
	else
		*addr = 0;
}

int
adf_put_admin_msg_sync(struct adf_accel_dev *accel_dev,
		       u32 ae,
		       void *in,
		       void *out)
{
	struct adf_admin_comms *admin = accel_dev->admin;
	struct adf_hw_device_data *hw_data = accel_dev->hw_device;
	struct resource *mailbox = admin->mailbox_addr;
	struct admin_info admin_csrs_info;

	hw_data->get_admin_info(&admin_csrs_info);
	int offset = ae * ADF_ADMINMSG_LEN * 2;
	int mb_offset =
	    ae * ADF_MAILBOX_STRIDE + admin_csrs_info.mailbox_offset;

	int times, received;
	struct icp_qat_fw_init_admin_req *request = in;

	sx_xlock(&admin->lock);

	if (ADF_CSR_RD(mailbox, mb_offset) == 1) {
		sx_xunlock(&admin->lock);
		return EAGAIN;
	}

	memcpy(admin->virt_addr + offset, in, ADF_ADMINMSG_LEN);
	ADF_CSR_WR(mailbox, mb_offset, 1);
	received = 0;
	for (times = 0; times < ADF_ADMIN_POLL_RETRIES; times++) {
		usleep_range(ADF_ADMIN_POLL_INTERVAL_US,
			     ADF_ADMIN_POLL_INTERVAL_US * 2);
		if (ADF_CSR_RD(mailbox, mb_offset) == 0) {
			received = 1;
			break;
		}
	}
	if (received)
		memcpy(out,
		       admin->virt_addr + offset + ADF_ADMINMSG_LEN,
		       ADF_ADMINMSG_LEN);
	else
		device_printf(GET_DEV(accel_dev),
			      "Failed to send admin msg %d to accelerator %d\n",
			      request->cmd_id,
			      ae);

	sx_xunlock(&admin->lock);
	return received ? 0 : EFAULT;
}

static inline int
adf_set_dc_ibuf(struct adf_accel_dev *accel_dev,
		struct icp_qat_fw_init_admin_req *req)
{
	char val[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = { 0 };
	unsigned long ibuf_size = 0;

	if (!adf_cfg_get_param_value(
		accel_dev, ADF_GENERAL_SEC, ADF_INTER_BUF_SIZE, val)) {
		if (compat_strtoul(val, 0, &ibuf_size))
			return EFAULT;
	}

	if (ibuf_size != 32 && ibuf_size != 64)
		ibuf_size = 64;

	req->ibuf_size_in_kb = ibuf_size;

	return 0;
}

int
adf_send_admin(struct adf_accel_dev *accel_dev,
	       struct icp_qat_fw_init_admin_req *req,
	       struct icp_qat_fw_init_admin_resp *resp,
	       u32 ae_mask)
{
	int i;
	unsigned int mask;

	for (i = 0, mask = ae_mask; mask; i++, mask >>= 1) {
		if (!(mask & 1))
			continue;
		if (adf_put_admin_msg_sync(accel_dev, i, req, resp) ||
		    resp->status)
			return EFAULT;
	}

	return 0;
}

static int
adf_init_me(struct adf_accel_dev *accel_dev)
{
	struct icp_qat_fw_init_admin_req req;
	struct icp_qat_fw_init_admin_resp resp;
	struct adf_hw_device_data *hw_device = accel_dev->hw_device;
	u32 ae_mask = hw_device->ae_mask;

	explicit_bzero(&req, sizeof(req));
	explicit_bzero(&resp, sizeof(resp));
	req.cmd_id = ICP_QAT_FW_INIT_ME;

	if (adf_set_dc_ibuf(accel_dev, &req))
		return EFAULT;
	if (accel_dev->aram_info) {
		req.init_cfg_sz = sizeof(*accel_dev->aram_info);
		req.init_cfg_ptr = (u64)accel_dev->admin->aram_map_phys_addr;
	}
	if (adf_send_admin(accel_dev, &req, &resp, ae_mask))
		return EFAULT;

	return 0;
}

static int
adf_set_heartbeat_timer(struct adf_accel_dev *accel_dev)
{
	struct icp_qat_fw_init_admin_req req;
	struct icp_qat_fw_init_admin_resp resp;
	struct adf_hw_device_data *hw_device = accel_dev->hw_device;
	u32 ae_mask = hw_device->ae_mask;
	u32 heartbeat_ticks;

	explicit_bzero(&req, sizeof(req));
	req.cmd_id = ICP_QAT_FW_HEARTBEAT_TIMER_SET;
	req.hb_cfg_ptr = accel_dev->admin->phy_hb_addr;
	if (adf_get_hb_timer(accel_dev, &heartbeat_ticks))
		return EINVAL;
	req.heartbeat_ticks = heartbeat_ticks;

	if (adf_send_admin(accel_dev, &req, &resp, ae_mask))
		return EFAULT;

	return 0;
}

static int
adf_get_dc_capabilities(struct adf_accel_dev *accel_dev, u32 *capabilities)
{
	struct icp_qat_fw_init_admin_req req;
	struct icp_qat_fw_init_admin_resp resp;
	u32 ae_mask = 1;

	explicit_bzero(&req, sizeof(req));
	req.cmd_id = ICP_QAT_FW_COMP_CAPABILITY_GET;

	if (adf_send_admin(accel_dev, &req, &resp, ae_mask))
		return EFAULT;

	*capabilities = resp.extended_features;

	return 0;
}

static int
adf_set_fw_constants(struct adf_accel_dev *accel_dev)
{
	struct icp_qat_fw_init_admin_req req;
	struct icp_qat_fw_init_admin_resp resp;
	struct adf_hw_device_data *hw_device = accel_dev->hw_device;
	u32 ae_mask = hw_device->admin_ae_mask;

	explicit_bzero(&req, sizeof(req));
	req.cmd_id = ICP_QAT_FW_CONSTANTS_CFG;

	req.init_cfg_sz = sizeof(const_tab);
	req.init_cfg_ptr = accel_dev->admin->const_tbl_addr;

	if (adf_send_admin(accel_dev, &req, &resp, ae_mask))
		return EFAULT;

	return 0;
}

static int
adf_get_fw_status(struct adf_accel_dev *accel_dev,
		  u8 *major,
		  u8 *minor,
		  u8 *patch)
{
	struct icp_qat_fw_init_admin_req req;
	struct icp_qat_fw_init_admin_resp resp;
	u32 ae_mask = 1;

	explicit_bzero(&req, sizeof(req));
	req.cmd_id = ICP_QAT_FW_STATUS_GET;

	if (adf_send_admin(accel_dev, &req, &resp, ae_mask))
		return EFAULT;

	*major = resp.version_major_num;
	*minor = resp.version_minor_num;
	*patch = resp.version_patch_num;

	return 0;
}

int
adf_get_fw_timestamp(struct adf_accel_dev *accel_dev, u64 *timestamp)
{
	struct icp_qat_fw_init_admin_req req;
	struct icp_qat_fw_init_admin_resp rsp;
	unsigned int ae_mask = 1;

	if (!accel_dev || !timestamp)
		return EFAULT;

	explicit_bzero(&req, sizeof(req));
	req.cmd_id = ICP_QAT_FW_TIMER_GET;

	if (adf_send_admin(accel_dev, &req, &rsp, ae_mask))
		return EFAULT;

	*timestamp = rsp.timestamp;
	return 0;
}

int
adf_get_fw_pke_stats(struct adf_accel_dev *accel_dev,
		     u64 *suc_count,
		     u64 *unsuc_count)
{
	struct icp_qat_fw_init_admin_req req = { 0 };
	struct icp_qat_fw_init_admin_resp resp = { 0 };
	unsigned long sym_ae_msk = 0;
	u8 sym_ae_msk_size = 0;
	u8 i = 0;

	if (!suc_count || !unsuc_count)
		return EFAULT;

	sym_ae_msk = accel_dev->au_info->sym_ae_msk;
	sym_ae_msk_size =
	    sizeof(accel_dev->au_info->sym_ae_msk) * BITS_PER_BYTE;

	req.cmd_id = ICP_QAT_FW_PKE_REPLAY_STATS_GET;
	for_each_set_bit(i, &sym_ae_msk, sym_ae_msk_size)
	{
		memset(&resp, 0, sizeof(struct icp_qat_fw_init_admin_resp));
		if (adf_put_admin_msg_sync(accel_dev, i, &req, &resp) ||
		    resp.status) {
			return EFAULT;
		}
		*suc_count += resp.successful_count;
		*unsuc_count += resp.unsuccessful_count;
	}
	return 0;
}

/**
 * adf_send_admin_init() - Function sends init message to FW
 * @accel_dev: Pointer to acceleration device.
 *
 * Function sends admin init message to the FW
 *
 * Return: 0 on success, error code otherwise.
 */
int
adf_send_admin_init(struct adf_accel_dev *accel_dev)
{
	int ret;
	u32 dc_capabilities = 0;
	unsigned int storage_enabled = 0;

	if (GET_HW_DATA(accel_dev)->query_storage_cap) {
		ret = adf_get_dc_capabilities(accel_dev, &dc_capabilities);
		if (ret) {
			device_printf(GET_DEV(accel_dev),
				      "Cannot get dc capabilities\n");
			return ret;
		}
		accel_dev->hw_device->extended_dc_capabilities =
		    dc_capabilities;
	} else {
		ret = GET_HW_DATA(accel_dev)->get_storage_enabled(
		    accel_dev, &storage_enabled);
		if (ret) {
			device_printf(GET_DEV(accel_dev),
				      "Cannot get storage enabled\n");
			return ret;
		}
	}

	ret = adf_set_heartbeat_timer(accel_dev);
	if (ret) {
		if (ret == EINVAL) {
			device_printf(GET_DEV(accel_dev),
				      "Cannot set heartbeat timer\n");
			return ret;
		}
		device_printf(GET_DEV(accel_dev),
			      "Heartbeat is not supported\n");
	}

	ret = adf_get_fw_status(accel_dev,
				&accel_dev->fw_versions.fw_version_major,
				&accel_dev->fw_versions.fw_version_minor,
				&accel_dev->fw_versions.fw_version_patch);
	if (ret) {
		device_printf(GET_DEV(accel_dev), "Cannot get fw version\n");
		return ret;
	}

	device_printf(GET_DEV(accel_dev),
		      "FW version: %d.%d.%d\n",
		      accel_dev->fw_versions.fw_version_major,
		      accel_dev->fw_versions.fw_version_minor,
		      accel_dev->fw_versions.fw_version_patch);

	ret = adf_set_fw_constants(accel_dev);
	if (ret) {
		device_printf(GET_DEV(accel_dev), "Cannot set fw constants\n");
		return ret;
	}

	ret = adf_init_me(accel_dev);
	if (ret)
		device_printf(GET_DEV(accel_dev), "Cannot init AE\n");

	return ret;
}

int
adf_init_admin_comms(struct adf_accel_dev *accel_dev)
{
	struct adf_admin_comms *admin = NULL;
	struct adf_hw_device_data *hw_data = NULL;
	struct adf_bar *pmisc = NULL;
	struct resource *csr = NULL;
	struct admin_info admin_csrs_info;
	unsigned int adminmsg_u, adminmsg_l;
	u64 reg_val = 0;
	int ret = 0;

	admin = kzalloc_node(sizeof(*accel_dev->admin),
			     M_WAITOK | M_ZERO,
			     dev_to_node(GET_DEV(accel_dev)));
	hw_data = accel_dev->hw_device;
	pmisc = &GET_BARS(accel_dev)[hw_data->get_misc_bar_id(hw_data)];
	csr = pmisc->virt_addr;
	ret = bus_dma_mem_create(&admin->dma_mem,
				 accel_dev->dma_tag,
				 FREEBSD_ALLIGNMENT_SIZE,
				 BUS_SPACE_MAXADDR,
				 PAGE_SIZE,
				 0);
	if (ret != 0) {
		device_printf(GET_DEV(accel_dev),
			      "Failed to allocate dma buff\n");
		kfree(admin);
		return ret;
	}
	admin->virt_addr = admin->dma_mem.dma_vaddr;
	admin->phy_addr = admin->dma_mem.dma_baddr;
	bzero(admin->virt_addr, PAGE_SIZE);

	ret = bus_dmamap_create(accel_dev->dma_tag, 0, &admin->const_tbl_map);
	if (ret != 0) {
		device_printf(GET_DEV(accel_dev), "Failed to create DMA map\n");
		bus_dma_mem_free(&admin->dma_mem);
		kfree(admin);
		return ret;
	}

	ret = bus_dmamap_load(accel_dev->dma_tag,
			      admin->const_tbl_map,
			      (void *)const_tab,
			      1024,
			      dma_callback,
			      &admin->const_tbl_addr,
			      BUS_DMA_NOWAIT);
	if (ret == 0 && admin->const_tbl_addr == 0)
		ret = EFBIG;
	if (ret != 0) {
		device_printf(GET_DEV(accel_dev),
			      "Failed to map const table for DMA\n");
		bus_dmamap_destroy(accel_dev->dma_tag, admin->const_tbl_map);
		bus_dma_mem_free(&admin->dma_mem);
		kfree(admin);
		return ret;
	}

	/* DMA ARAM address map */
	if (accel_dev->aram_info) {
		ret =
		    bus_dmamap_create(accel_dev->dma_tag, 0, &admin->aram_map);
		if (ret != 0) {
			device_printf(GET_DEV(accel_dev),
				      "Failed to create DMA map\n");
			bus_dma_mem_free(&admin->dma_mem);
			kfree(admin);
			return ret;
		}
		ret = bus_dmamap_load(accel_dev->dma_tag,
				      admin->aram_map,
				      (void *)accel_dev->aram_info,
				      sizeof(*accel_dev->aram_info),
				      dma_callback,
				      &admin->aram_map_phys_addr,
				      BUS_DMA_NOWAIT);

		if (ret == 0 && admin->aram_map_phys_addr == 0)
			ret = EFBIG;
		if (ret != 0) {
			device_printf(GET_DEV(accel_dev),
				      "Failed to map aram phys addr for DMA\n");
			bus_dmamap_destroy(accel_dev->dma_tag, admin->aram_map);
			bus_dma_mem_free(&admin->dma_mem);
			kfree(admin);
			return ret;
		}
	}

	ret = bus_dma_mem_create(&admin->dma_hb,
				 accel_dev->dma_tag,
				 FREEBSD_ALLIGNMENT_SIZE,
				 BUS_SPACE_MAXADDR,
				 PAGE_SIZE,
				 0);
	if (ret != 0) {
		device_printf(GET_DEV(accel_dev),
			      "Failed to allocate dma buff\n");
		bus_dmamap_unload(accel_dev->dma_tag, admin->const_tbl_map);
		bus_dmamap_destroy(accel_dev->dma_tag, admin->const_tbl_map);
		bus_dma_mem_free(&admin->dma_mem);
		kfree(admin);
		return ret;
	}

	admin->virt_hb_addr = admin->dma_hb.dma_vaddr;
	admin->phy_hb_addr = admin->dma_hb.dma_baddr;
	bzero(admin->virt_hb_addr, PAGE_SIZE);

	hw_data->get_admin_info(&admin_csrs_info);

	adminmsg_u = admin_csrs_info.admin_msg_ur;
	adminmsg_l = admin_csrs_info.admin_msg_lr;
	reg_val = (u64)admin->phy_addr;
	ADF_CSR_WR(csr, adminmsg_u, reg_val >> 32);
	ADF_CSR_WR(csr, adminmsg_l, reg_val);
	sx_init(&admin->lock, "qat admin");
	admin->mailbox_addr = csr;
	accel_dev->admin = admin;
	return 0;
}

void
adf_exit_admin_comms(struct adf_accel_dev *accel_dev)
{
	struct adf_admin_comms *admin = accel_dev->admin;

	if (!admin)
		return;

	if (admin->virt_addr)
		bus_dma_mem_free(&admin->dma_mem);

	if (admin->virt_hb_addr)
		bus_dma_mem_free(&admin->dma_hb);

	bus_dmamap_unload(accel_dev->dma_tag, admin->const_tbl_map);
	bus_dmamap_destroy(accel_dev->dma_tag, admin->const_tbl_map);
	sx_destroy(&admin->lock);
	kfree(admin);
	accel_dev->admin = NULL;
}
